﻿using DLLPC.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace VisionCore
{
    public class KeyenceHelper
    {
        private TcpClient tcpClient = new TcpClient();
        private string ip = "192.168.0.60";
        private int port = 8001;
        private CtrlCMD setCMD ;
        private SystemTimeCounter scTimeOut = new SystemTimeCounter();

        public bool IsError { get; set; } = false;
        public bool IsRun { get; set; } = true;

        public bool Sending { get; set; } = false;

        public SafeQueue<CtrlCMD> SQ_SendCMD = new SafeQueue<CtrlCMD>();

        public Action<CtrlCMD, string> CallBackEventHandler = null;

        public bool Connect(string ip, int port)
        {
            this.ip = ip;
            this.port = port;
            IPAddress host = IPAddress.Parse(ip);
            try
            {
                if (tcpClient == null || tcpClient.Client == null)
                {
                    tcpClient = new TcpClient();
                }

                tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 200);
                tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 200);

                if (!tcpClient.Connected)
                {
                    tcpClient.Connect(host, port);

                    if (tcpClient.Client.Available > 0)
                    {
                        byte[] tReceiveData = new byte[512];
                        int tCount = tcpClient.Client.Receive(tReceiveData);
                        string tReturnData = ASCIIEncoding.ASCII.GetString(tReceiveData).Trim();
                        LogMsg(tReturnData);
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                LogMsg("TcpClient Connect Error: " + ex.Message);
                tcpClient.Close();
                return false;
            }
        }

        public void DisConnect()
        {
            try
            {
                if (tcpClient.Connected)
                {
                    tcpClient.Close();
                }
            }
            catch (Exception ex)
            {
                LogMsg("TcpClient DisConnect Error: " + ex.Message);
            }
        }

        public bool InitialFunction()
        {
            return true;
        }

        public bool PollingFunction()
        {
            try
            {
                if (SQ_SendCMD.Count > 0 && !Sending)
                {
                    CtrlCMD tSetCMD = SQ_SendCMD.Dequeue();
                    setCMD = tSetCMD;
                    byte[] tSendData = ASCIIEncoding.ASCII.GetBytes(tSetCMD.CMD);
                    tcpClient.Client.Send(tSendData, tSendData.Length, SocketFlags.None);

                    Sending = true;
                    Thread.Sleep(50);
                    scTimeOut.Start();
                }

                if (tcpClient.Client.Available > 0)
                {
                    byte[] arrMsgRec = new byte[512];
                    int len = tcpClient.Client.Receive(arrMsgRec);

                    if (len == 0) return true;
                    string tReturnData = ASCIIEncoding.ASCII.GetString(arrMsgRec).Trim();

                    if (CallBackEventHandler != null)
                    {
                        CallBackEventHandler(setCMD, tReturnData);
                    }

                    Sending = false;
                }

                if (SQ_SendCMD.Count > 0 && Sending)
                {
                    if (scTimeOut.Duration > 100)
                    {
                        Sending = false;
                    }
                }

                if (SQ_SendCMD.Count > 0)
                {
                    if (scTimeOut.Duration > 3000)
                    {
                        Sending = false;
                        LogMsg("Wait Report TimeOut?");
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                LogMsg("Read/Write Value Error: " + ex.Message);
                return false;
            }
        }

        private void LogMsg(string msg)
        {
            LogHelper.Write(LogHelper.Module.Exception, string.Format("{0} {1}: {2}", ip, port, msg));
        }

        public class CtrlCMD
        {
            public string CMD { get; set; }

            public string Name { get; set; }

            public int BlockNo { get; set; }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="type">1:WX 2:RX</param>
            /// <param name="vCMD"></param>
            public CtrlCMD(typeMode type, string vCMD="", int blockNo = 0)
            {
                switch (type)
                {
                    case typeMode.RX:
                        {
                            CMD = "RX," + vCMD + "\r";
                            Name = "RX";
                        }
                        break;
                    case typeMode.WX:
                        {
                            CMD = "WX," + vCMD + "\r";
                            Name = "WX";
                        }
                        break;
                    case typeMode.Ready:
                        {
                            CMD = "RX,Ready" + "\r";
                            Name = "Ready";
                        }
                        break;
                    case typeMode.Error:
                        {
                            CMD = "RX,Error" + "\r";
                            Name = "Error";
                        }
                        break;
                    case typeMode.ProgramNo:
                        {
                            CMD = "RX,ProgramNo" + "\r";
                            Name = "ProgramNo";
                        }
                        break;
                    case typeMode.BlockNoParam:
                        {
                            CMD = "RX," + vCMD + "\r";
                            Name = "BlockNo";
                        }
                        break;
                    case typeMode.MarkingParameter:
                        {
                            CMD = "RX," + vCMD + "\r";
                            Name = "MarkingParameter";
                        }
                        break;
                    case typeMode.StartMarking:
                        {
                            CMD = "WX,StartMarking" + "\r";
                            Name = "StartMarking";
                        }
                        break;
                    case typeMode.LaserPowerCheck:
                        {
                            CMD = "WX,LaserPowerCheck=" + vCMD + "\r";
                            Name = "LaserPowerCheck";
                        }
                        break;

                }

                BlockNo = blockNo;
            }

            public enum typeMode
            {
                RX,
                WX,
                Ready,
                Error,
                ProgramNo,
                BlockNoParam,
                MarkingParameter,
                LaserPowerCheck,
                StartMarking
            }
        }
    }
}
